package com.example.financeapi.controller.miniapp;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.alibaba.fastjson.JSONObject;
import com.example.financeapi.config.constant.APIConstant;
import com.example.financeapi.config.annotation.PassToken;
import com.example.financeapi.config.wechat.miniapp.WxMaConfiguration;
import com.example.financeapi.config.wechat.miniapp.WxMaProperties;
import com.example.financeapi.entity.FTaskErrorLog;
import com.example.financeapi.entity.FUser;
import com.example.financeapi.enums.ResultEnum;
import com.example.financeapi.mapper.FTaskErrorLogMapper;
import com.example.financeapi.service.FUserService;
import com.example.financeapi.utils.*;
import com.example.financeapi.entity.vo.ResultException;
import com.example.financeapi.entity.vo.ResultVOUtil;
import com.example.financeapi.entity.vo.ResultVo;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信小程序用户接口
 * @author Alvin
 */
@RestController
@RequestMapping("/wx/miniapp/user")
public class WxMaUserController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private FUserService fUserService;
    @Autowired
    private WxMaProperties wxMaProperties;
    @Autowired
    private FTaskErrorLogMapper fTaskErrorLogMapper;

    /**
     * 小程序登陆接口
     * @param code
     * @param response
     * @return
     */
    @GetMapping("/login")
    public ResultVo login(String code, HttpServletResponse response) {
        if (StringUtils.isBlank(code)) {
            return ResultVOUtil.error("code"+ ResultEnum.PARAM_IS_NULL.getMessage());
        }
        String getAppId =wxMaProperties.getConfigs().get(0).getAppid();
        final WxMaService wxService = WxMaConfiguration.getMaService(getAppId);
        try {
            String token="";
            FUser getFUser =new FUser();
            Map<String, Object> paramMap =new HashMap<>();
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
            this.logger.info("【微信小程序用登陆接口 login】 getSessionKey={},getOpenid={},getUnionid={},session={}",
                    session.getSessionKey(),session.getOpenid(),session.getUnionid(),session);
            String getUnionID=session.getUnionid();
            paramMap.put("unionid",session.getUnionid());
            getFUser.setUnionid(getUnionID);
            getFUser.setMiniappOpenid(session.getOpenid());
            FUser FUser =fUserService.getFUserByCode(paramMap);
            if(FUser==null){
                getFUser =fUserService.insert(getFUser);
                if(getFUser!=null){
                    String id =getFUser.getId()+"";
                    if(!"0".equals(id)){
                        redisUtils.set(id,getUnionID, APIConstant.JWT_TOKEN_TIMES);
                        //生成token
                        token = JWTUtils.createJWT(id, APIConstant.JWT_TOKEN_TIMES);
                        //记录token 测试用
                        redisUtils.set(getUnionID,token, APIConstant.JWT_TOKEN_TIMES);
                    }
                }
            }else{
                String id =FUser.getId()+"";
                if(!"0".equals(id)){
                    paramMap.put("miniappOpenid",session.getOpenid());
                    FUser fUsers =fUserService.getFUserByCode(paramMap);
                    if(fUsers ==null){
                        getFUser =new FUser();
                        getFUser.setId(FUser.getId());
                        getFUser.setMiniappOpenid(session.getOpenid());
                        fUserService.update(getFUser);
                    }
                    redisUtils.del(id);
                    redisUtils.del(getUnionID);
                    redisUtils.set(id,getUnionID, APIConstant.JWT_TOKEN_TIMES);
                    //生成token
                    token = JWTUtils.createJWT(id, APIConstant.JWT_TOKEN_TIMES);
                    //记录token 测试用
                    redisUtils.set(getUnionID,token, APIConstant.JWT_TOKEN_TIMES);
                }
            }

            if(StringUtils.isBlank(token)){
                return ResultVOUtil.error(token);
            }
            return ResultVOUtil.success(token);
        } catch (WxErrorException | ResultException e) {
            FTaskErrorLog fTaskErrorLog =new FTaskErrorLog();
            fTaskErrorLog.setTaskName(this.getClass().getName());
            fTaskErrorLog.setMessage(e.getMessage());
            fTaskErrorLog.setCause(e.getCause()+"");
            fTaskErrorLogMapper.insert(fTaskErrorLog);
            logger.error("【WxMaUserController.login】出现异常：{}，原因：{}", e.getMessage(), e.getCause());
            this.logger.error(e.getMessage(), e);
            return ResultVOUtil.error(e.getMessage(),e);
        }
    }

    /**
     * 获取用户信息接口
     * @param appid
     * @param sessionKey
     * @param signature
     * @param rawData
     * @param encryptedData
     * @param iv
     * @return
     */
    @GetMapping("/info")
    public String info(@PathVariable String appid, String sessionKey,
                       String signature, String rawData, String encryptedData, String iv) {
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        // 用户信息校验
        if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
            return "user check failed";
        }

        // 解密用户信息
        WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);

        return JsonUtils.toJson(userInfo);
    }

    /**
     * 获取用户绑定手机号信息
     * @param appid
     * @param sessionKey
     * @param signature
     * @param rawData
     * @param encryptedData
     * @param iv
     * @return
     */
    @GetMapping("/phone")
    public String phone(@PathVariable String appid, String sessionKey, String signature,
                        String rawData, String encryptedData, String iv) {
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        // 用户信息校验
        if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
            return "user check failed";
        }

        // 解密
        WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);

        return JsonUtils.toJson(phoneNoInfo);
    }

    /**
     * 获取微信小程序的AccessToken
     * @param flag
     * @return
     */
    @PassToken
    @GetMapping("/getAccessToken")
    public String getAccessToken(String flag){
        String getAccessToken ="";
        try {
            JSONObject tokenJson =new JSONObject();
            String getMyAppId="";
            String getMyAppSecret="";
            if(StringUtils.isEmpty(flag)){
                getMyAppId =wxMaProperties.getConfigs().get(0).getAppid();
                getMyAppSecret =wxMaProperties.getConfigs().get(0).getSecret();
            }else{
                getMyAppId =wxMaProperties.getConfigs().get(1).getAppid();
                getMyAppSecret =wxMaProperties.getConfigs().get(1).getSecret();
            }
            getAccessToken =redisUtils.get("miniapp_access_token-"+getMyAppId);
            if(StringUtils.isEmpty(getAccessToken)){
                //获取token
                String getTokenApi = String.format(APIConstant.MX_ACCESS_TOKEN_URL, getMyAppId, getMyAppSecret);
                String tokenJsonStr = HttpUtil.doGetPost(getTokenApi, "GET", null);
                logger.info("【微信小程序用登陆接口 getUnionID】获取ACCESS_TOKEN请求结果： tokenJsonStr={}",tokenJsonStr);
                tokenJson = JSONObject.parseObject(tokenJsonStr);
                getAccessToken = (String) tokenJson.get("access_token");
                redisUtils.set("miniapp_access_token-"+getMyAppId,getAccessToken, APIConstant.TOKEN_TIMES);
            }
            if(getAccessToken==null){
                return tokenJson.toJSONString();
            }
           return getAccessToken;
        }catch (Exception e){
            FTaskErrorLog fTaskErrorLog =new FTaskErrorLog();
            fTaskErrorLog.setTaskName(this.getClass().getName());
            fTaskErrorLog.setMessage(e.getMessage());
            fTaskErrorLog.setCause(e.getCause()+"");
            fTaskErrorLogMapper.insert(fTaskErrorLog);
            logger.error("【WxMaUserController.getAccessToken】出现异常：{}，原因：{}", e.getMessage(), e.getCause());
            throw new RuntimeException(e.getMessage(),e);
        }
    }

    /**
     * 获取微信小程序 UnoinId
     * 小程序token：
     *   https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx78f9d87243c79486&secret=43c50e783a978c0c53754db93cf68d31&code=033tsUQf2ysd1H04d9Pf2ckXQf2tsUQ3&grant_type=authorization_code
     * @param openid
     * @return
     */

    /**
     * 获取微信小程序的AccessToken
     * 小程序token：https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx78f9d87243c79486&secret=43c50e783a978c0c53754db93cf68d31&code=033tsUQf2ysd1H04d9Pf2ckXQf2tsUQ3&grant_type=authorization_code
     * @param openid
     * @param flag
     * @return
     */
    @PassToken
    @GetMapping("/getUnionID")
    public String getUnionID(@RequestParam String openid,String flag){
        String unionID ="";
        String getAccessToken ="";
        try {
            JSONObject tokenJson =new JSONObject();
            String getMyAppId ="";
            String getMyAppSecret ="";
            if(StringUtils.isEmpty(flag)){
                getMyAppId =wxMaProperties.getConfigs().get(0).getAppid();
                getMyAppSecret =wxMaProperties.getConfigs().get(0).getSecret();
            }else{
                getMyAppId =wxMaProperties.getConfigs().get(1).getAppid();
                getMyAppSecret =wxMaProperties.getConfigs().get(1).getSecret();
            }
            getAccessToken =redisUtils.get("miniapp_access_token-"+getMyAppId);
            if(StringUtils.isEmpty(getAccessToken)){
                //获取token
                String getTokenApi = String.format(APIConstant.MX_ACCESS_TOKEN_URL, getMyAppId, getMyAppSecret);
                String tokenJsonStr = HttpUtil.doGetPost(getTokenApi, "GET", null);
                logger.info("【微信小程序用登陆接口 getUnionID】获取ACCESS_TOKEN请求结果： tokenJsonStr={}",tokenJsonStr);
                tokenJson = JSONObject.parseObject(tokenJsonStr);
                getAccessToken = (String) tokenJson.get("access_token");
                redisUtils.set("miniapp_access_token-"+getMyAppId,getAccessToken, APIConstant.TOKEN_TIMES);
            }
            if(getAccessToken==null){
                return tokenJson.toJSONString();
            }
            //获取unionid
            String getUnionIDApi = String.format(APIConstant.GET_MINIAPP_UNIONID_URL,getAccessToken,openid);
            String JsonStr = HttpUtil.doGetPost(getUnionIDApi,"GET",null);
            JSONObject jsonObj = JSONObject.parseObject(JsonStr);
            logger.info("【微信小程序用登陆接口 getUnionID】获取getUnionID： jsonObj={}",jsonObj);
            if(StringUtils.isNotEmpty(jsonObj.get("unionid")+"")){
                unionID= (String) jsonObj.get("unionid");
                if(unionID==null){
                    return jsonObj.toJSONString();
                }
            }else{
                throw new RuntimeException("获取unionid失败！jsonObj={}"+jsonObj);
            }
        }catch (Exception e){
            FTaskErrorLog fTaskErrorLog =new FTaskErrorLog();
            fTaskErrorLog.setTaskName(this.getClass().getName());
            fTaskErrorLog.setMessage(e.getMessage());
            fTaskErrorLog.setCause(e.getCause()+"");
            fTaskErrorLogMapper.insert(fTaskErrorLog);
            logger.error("【WxMaUserController.getUnionID】出现异常：{}，原因：{}", e.getMessage(), e.getCause());
            throw new RuntimeException(e.getMessage(),e);
        }
        return unionID;
    }

    /**
     * 详情看官方文档 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/qr-code.html
     * 此处以官方接口B为例 生成小程序码，可接受页面参数较短，生成个数不受限
     * @param page 需要跳转的页面地址 例如：page/index/index
     * @param param 参数 例如：123
     * @param flag
     * @param response
     */
    @PassToken
    @RequestMapping("/getWXCode")
    public void getWXCode(@RequestParam(defaultValue = "page/index/index", value = "page") String page,
                                 @RequestParam(defaultValue = "123", value = "param")String param,String flag,
                                 HttpServletResponse response) {
        OutputStream stream = null;
        try {
            //获取AccessToken
            String getMyAppId ="";
            String getMyAppSecret ="";
            if(StringUtils.isEmpty(flag)){
                getMyAppId =wxMaProperties.getConfigs().get(0).getAppid();
                getMyAppSecret =wxMaProperties.getConfigs().get(0).getSecret();
            }else{
                getMyAppId =wxMaProperties.getConfigs().get(1).getAppid();
                getMyAppSecret =wxMaProperties.getConfigs().get(1).getSecret();
                page="page/component/index";
            }
            String getAccessToken =redisUtils.get("miniapp_access_token-"+getMyAppId);
            if(getAccessToken==null){
                //获取token
                String getTokenApi = String.format(APIConstant.MX_ACCESS_TOKEN_URL, getMyAppId, getMyAppSecret);
                String tokenJsonStr = HttpUtil.doGetPost(getTokenApi, "GET", null);
                JSONObject tokenJson = JSONObject.parseObject(tokenJsonStr);
                getAccessToken = (String) tokenJson.get("access_token");
                logger.info("【微信小程序用登陆接口 getWXCode】获取ACCESS_TOKEN： tokenJson={}",tokenJson);
                redisUtils.set("miniapp_access_token-"+getMyAppId,getAccessToken, APIConstant.TOKEN_TIMES);
            }
            //设置响应类型
            response.setContentType("image/png");
            String getWXCodeApi = String.format(APIConstant.MINIAPP_GETWXCODE2_URL,getAccessToken);
            logger.info("【微信小程序用登陆接口 getWXCode】获取 getWXCodeApi： getWXCodeApi={}",getWXCodeApi);
            //组装参数
            Map<String, Object> paraMap = new HashMap<>();
            //二维码携带参数 不超过32位 参数类型必须是字符串
            paraMap.put("scene", param);
            //二维码跳转页面
            paraMap.put("page", page);
            //二维码的宽度
            paraMap.put("width", "450");
            //自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调
            paraMap.put("auto_color", false);
            //是否需要透明底色， is_hyaline 为true时，生成透明底色的小程序码
            paraMap.put("is_hyaline", false);
            //执行post 获取数据流
            byte[] result = HttpClientUtils.doImgPost(getWXCodeApi, paraMap);
            //byte[] result = HttpUtil.sendHttpPost(getWXCodeApi,paraMap);
            stream = response.getOutputStream();
            stream.write(result);
            stream.flush();
            stream.close();
        } catch (IOException e) {
            FTaskErrorLog fTaskErrorLog =new FTaskErrorLog();
            fTaskErrorLog.setTaskName(this.getClass().getName());
            fTaskErrorLog.setMessage(e.getMessage());
            fTaskErrorLog.setCause(e.getCause()+"");
            fTaskErrorLogMapper.insert(fTaskErrorLog);
            logger.error("【WxMaUserController.getWXCode】出现异常：{}，原因：{}", e.getMessage(), e.getCause());
        }
    }

}
